//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "ddk.h"
#include <stdio.h>
#include <time.h>
#include <ctype.h>

#include <misc.h>
#include <ktime.h>
#include <hash.h>
#include <fat.h>
#include <fatfile.h>

#ifdef _MSC_VER
#pragma warning(disable:4172)
#endif

/*
 * inum()
 *    Synthesize an "inode" number for the node
 */
UInt32
inum(struct node *n)
{
    return(n->n_inum);
}

/*
 * isize()
 *    Calculate size of file from its "inode" information
 */
UInt32 FatDir::
isize(struct node *n)
{
    if (n == p_Sharedata->rootdir) {
        return(sizeof(struct directory)*p_Sharedata->dirents);
    }
    return(n->n_clust->c_nclust*p_Sharedata->clsize);
}

/*
 * fatfs_acc()
 *    Give access string based on dir entry protection attribute
 */
UInt32 FatDir::
fatfs_acc(struct directory *d)
{
    if (d->DIR_Attr & DA_READONLY) {
        return 0x100;
    }

    return 0x80;
}

/*
 * fatfs_stat()
 *    Build stat string for file, send back
 */

#define MkFatINT32(_x_,_v_) *((UInt32*)(_x_)) = (UInt32)(_v_)

void FatDir::
fatfs_stat(class CFatFile *f, FILESTAT *pStat, UInt32 *pSizeRead)
{
    if (*pSizeRead) {
        fatfs_wstat(f, pStat, *pSizeRead);
        return;
    }
    struct node *n = f->f_node;
    struct directory d;
    timespec_o ts;

    int isdir = (n->n_type == T_DIR);

    /*
     * No dir entry for root, otherwise get a copy of it
     */
    if (n != p_Sharedata->procroot) {
        dir_copy(n->n_dir, n->n_slot, &d);
    }
    else {
        bzero(&d, sizeof(d));
    }

    pStat->mode = NULL;
    pStat->size = (isdir ? isize(n) : n->n_len);
    dos2unixtime(d.DIR_WrtDate, d.DIR_WrtTime, 0, &ts);
    pStat->mtime = ts.tv_sec;
    dos2unixtime(d.DIR_LstAccDate, 0, 0, &ts);
    pStat->atime = ts.tv_sec;
    dos2unixtime(d.DIR_CrtDate, d.DIR_CrtTime, d.DIR_CrtTimeTenth, &ts);
    pStat->ctime = ts.tv_sec;

    pStat->blocks = 0;
    pStat->blksize = 4096;

    *pSizeRead = sizeof(FILESTAT);
}

void FatDir::
fatfs_GetSize(class CFatFile *f, UInt64 *pSize)
{
    struct node *n = f->f_node;
    int isdir = (n->n_type == T_DIR);
    *pSize = (isdir ? isize(n) : n->n_len);

    return;
}

/*
 * fatfs_fid()
 *    Return ID for file
 */
int FatDir::
fatfs_fid(class CFatFile *f, UInt32 *iNUm, UInt32 *iSize)
{
    struct node *n = f->f_node;

    /*
     * Only *files* get an ID (and thus can be mapped shared)
     */
    if (n->n_type == T_DIR) {
        return EINVAL;
    }

    /*
     * Remember that this happened
     */
    n->n_flags |= N_FID;

    /*
     * arg is the inode value; arg1 is the size in pages
     */
    *iNUm = inum(n);
    *iSize = btorp(isize(n));

    return 0;
}

/*
 * accum_ro()
 *    Walk a protection label and see if it's writable
 */
int
accum_ro(PROT *p)
{
    UInt32 flags, x;

    flags = p->prot_default;
    for (x = 0; x < p->prot_len;++x) {
        flags |= p->prot_bits[x];
    }
    return((flags & ACC_WRITE) == 0);
}

/*
 * fatfs_wstat()
 *    Write status of FAT file
 *
 * We support setting of modification time only, plus the usual
 * shared code to set access to the filesystem.
 */
extern  PROT fatfs_prot;
int FatDir::
fatfs_wstat(class CFatFile *f, FILESTAT *pStat, UInt32 pSizeRead)
{
    PROT *prot, tmp_prot;
    struct node *n = f->f_node;
    struct directory d;
    int was_ro = 0;
//    STATSTG *pStat = (STATSTG *)buf;

    /*
     * Use the root protection node for root dir, a private
     * copy otherwise.
     */
    if (n == p_Sharedata->procroot) {
        prot = &fatfs_prot;
    }
    else {

        prot = &tmp_prot;
        tmp_prot = fatfs_prot;
        dir_copy(n->n_dir, n->n_slot, &d);
        was_ro = ((d.DIR_Attr & DA_READONLY) != 0);
    }

    if (pStat->mtime) {
        dir_timestamp(n, pStat->mtime);
    }

//    if (pStat->ctime) {
//        // create time cannot be changed
//    }

    if (pStat->atime) {
        dir_timeaccess(n, pStat->atime);
    }

//    if (pStat->type != 0) {
//        char *type;
//        if (pStat->type == 'd') {
//           type = "d";
//        }
//        else if (pStat->type == 'f') {
//           type = "f";
//        }
//        else if (pStat->type == 's'){
//           type = "symlink";
//        }
//        if (dir_set_type(f, type)) {
//           return EINVAL;
//        }
//    }
    sync();
#if 0
    /*
     * Common wstat handling code
     */
    if (do_wstat(m, prot, f->f_perm, &field, &val) == 0) {
        /*
         * If he changed the protection, map it back onto
         * the FAT dir entry.
         */
        if ((prot == &tmp_prot) &&
            (was_ro != accum_ro(prot))) {
            dir_readonly(f, !was_ro);
        }
        return;
    }
#endif

    /*
     * Return success
     */
    return 0;
}
